﻿var waitForFinalEvent = (function () {
    var timers = {};
    return function (callback, ms, uniqueId) {
        if (!uniqueId) {
            uniqueId = "Don't call this twice without a uniqueId";
        }
        if (timers[uniqueId]) {
            clearTimeout(timers[uniqueId]);
        }
        timers[uniqueId] = setTimeout(callback, ms);
    };
})();

var detailInfo = function (obj) {
    var s = '';
    for (var key in obj) {
        if (!obj.hasOwnProperty(key)) {
            continue;
        }
        if (typeof obj[key] === 'function') {
            s += key + '=' + obj[key]() + '\r\n';
        }
        else {
            s += key + '=' + obj[key] + '\r\n';
        }
    }
    return s;
};

$.fn.hasParent = function (objs) {
    var found = false;
    $(this[0]).parents().andSelf().each(function () {
        if (this == objs[0]) {
            found = true;
            return false;
        }
    });
    return found;
}
$.fn.hasAttr = function (name) {
    return this.attr(name) !== undefined && this.attr(name) !== false;
};
$.fn.guard = function (proc) {
    if (this.attr('clicked')) {
        return;
    }
    this.attr('clicked', true);
    proc();
    this.removeAttr('clicked');
};

$.fn.enable = function () {
    this.removeAttr('disabled');
    return this;
};
$.fn.disable = function () {
    this.attr('disabled', 'disabled');
    return this;
};

$.fn.left = function () {
    return this.offset().left;
};
$.fn.right = function () {
    return this.offset().left + this.outerWidth();
};
$.fn.top = function () {
    return this.offset().top;
};
$.fn.bottom = function () {
    return this.offset().top + this.outerHeight();
};

/* Docking */
function Dock(element, options) {
    this.element = element;
    this.options = $.extend({}, Dock.defaultOptions, options);
    if (!this.options.hoffset) {
        this.options.hoffset = this.options.offset;
    }
    if (!this.options.voffset) {
        this.options.voffset = this.options.offset;
    }

    this.update();
}
Dock.defaultOptions = {
    stretchDown: false,
    stretchRight: false,
    offset: 5,
    hoffset: null,
    voffset: null,
    absolute: true
};
Dock.settings = [];
$(window).resize(function () {
    for (var i = 0; i < Dock.settings.length; i++) {
        Dock.settings[i].update();
    }
});

Dock.prototype = {
    update: function () {
        if (this.options.absolute) {
            if (this.options.stretchRight) {
                this.element.width($(window).width() - this.element.offset().left - this.options.hoffset);
            }
            if (this.options.stretchDown) {
                this.element.height($(window).height() - this.element.offset().top - this.options.voffset);
            }
        }
        else {
            if (this.options.stretchRight) {
                this.element.css('max-width', $(window).width() - this.element.offset().left - this.options.hoffset);
            }
            if (this.options.stretchDown) {
                this.element.css('max-height', $(window).height() - this.element.offset().top - this.options.voffset);
            }
        }
    }
};

$.fn.dock = function (options) {
    if (TypeUtil.isString(options)) {
        var dock = this.data('data-dock');
        switch (options) {
            case 'update':
                dock.update();
                break;
            case 'remove':
                this.removeData();
                Dock.settings.splice(Dock.settings.indexOf(dock), 1);
                break;
        }
    }
    else {
        Dock.settings.push(new Dock(this, options));
    }
    return this;
};

ko.bindingHandlers.dock = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        $(element).dock(value);
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
    }
};


/* Popup Dialog */
$.fn.PopupDialog = function (options) {
};
PopupDialog.defaultOptions = {
    target: null,
    docks: null,
    cancelOnEsc: true,
    offset: 5,
    buttons: null
};
function PopupDialog(element, options) {
    this.element = element;
    this.options = $.extend({}, PopupDialog.defaultOptions, options);
    this.element.data("popupdialog", this);

    this.defaultButton = null;
    this.cancelButton = null;
    this.arrow = null;

    this.init();
}
PopupDialog.prototype = {
    init: function () {
        var self = this;

        if (this.options.target) {
            this.element.css('position', 'absolute');
            this.arrow = $('<img>').attr('src', 'images/arrow.png').css({
                position: 'absolute'
            }).prependTo(this.element);
        }

        if (this.options.buttons) {
            var target = this.options.buttons.target;
            for (var key in this.options.buttons) {
                if (key === "target") {
                    continue;
                }
                var value = this.options.buttons[key];

                var button = $('<a>').text(key).addClass('button').appendTo(target);
                if (typeof value === 'function') {
                    button.click(value)
                }
                else {
                    button.click(value.click);
                    if (this.options.type == 'default') {
                        this.defaultButton = button;
                    }
                    else if (this.options.type == 'cancel') {
                        this.cancelButton = button;
                    }
                }
                this.options.buttons.target.append('<span>&nbsp;&nbsp;</span>');
            }
            $('span:last', this.options.buttons.target).remove();
        }

        this.element.click(function (e) {
            e.stopPropagation();
        });
        $(document).click(function (e) {
            if ((!e.which || e.which == 1) && self.element.is(':visible')) {
                self.hide();
            }
        });
        $(window).resize(function (e) {
            if (self.element.is(':visible')) {
                self.updatePos();
            }
        });
        if (this.options.cancelOnEsc && this.cancelButton) {
            $(this.element).keydown(function (e) {
                if (e.which == 27) {
                    self.cancelButton.click();
                }
            });
        }
    },
    updatePos: function () {
        if (!this.options.target || !this.options.docks) {
            return;
        }
        this.element.hide().css({ left: 0, top: 0 });
        for (var i = 0; i < this.options.docks.length; i++) {
            switch (this.options.docks[i]) {
                case "left":
                    break;
                case "right":
                    break;
                case "top":
                    break;
                case "bottom":
                    break;
            }
        }

        var top = $(this.target).bottom() + 5;
        var left = $(this.target).left() + $(this.target).outerWidth() / 2 - this.element.outerWidth() / 2;
        if (left < this.options.offset) {
            left = this.options.offset;
        }
        if (left + this.element.outerWidth() > $(window).width() - this.options.offset) {
            left = $(window).width() - this.element.outerWidth() - this.options.offset;
        }

        this.element.css({
            left: left,
            top: top
        });
        //$('tbody', this.element).width(this.element.width());

        this.element.show();
        this.arrow.css('left', $(this.target).left() + $(this.target).outerWidth() / 2 - left - 7);
    }
};


/* Popup dialog */
$.fn.inlineDialog = function (options) {
    if (!this.data('inlineDialog')) {
        new InlineDialog(this, options);
    }
    else {
        var dialog = this.data('inlineDialog');
        switch (options.method) {
            case 'show':
                dialog.target = options.target;
                dialog.onbutton = options.onbutton;
                dialog.show();
                break;
            case 'hide':
                dialog.hide();
                break;
        }
    }

    return this;
};
function InlineDialog(element, options) {
    this.element = element;
    this.options = $.extend({}, InlineDialog.defaultOptions, options);
    this.onbutton = null;
    this.element.data('inlineDialog', this);

    this.init();
}
InlineDialog.defaultOptions = {
    dock: null,
    buttons: null,
    modal: false,
    closeOnEscape: true,
    offset: 5
};
InlineDialog.prototype = {
    init: function () {
        var self = this;

        this.element.css('position', 'absolute').data('inlineDialog', this);
        this.arrow = $('<img>').attr('src', 'images/arrow.png').css({
            position: 'absolute',
            top: -8
        }).prependTo(this.element).css({
            left: this.element.width() / 2 - 6
        });
        if (this.options.buttons) {
            var td = $('table > tfoot > tr > td', this.element);
            for (var i = 0; i < this.options.buttons.length; i++) {
                $('<a>').text(this.options.buttons[i]).addClass('button').attr('index', i).click(function () {
                    if (self.onbutton) {
                        self.onbutton($(this).attr('index') * 1);
                    }
                }).appendTo(td);
                td.append('<span>&nbsp;&nbsp;</span>');
            }
            $('span:last', td).remove();
        }

        this.element.click(function (e) {
            e.stopPropagation();
        });
        $(document).click(function (e) {
            if ((!e.which || e.which == 1) && self.element.is(':visible')) {
                self.hide();
            }
        });
        $(window).resize(function (e) {
            if (self.element.is(':visible')) {
                self.updatePos();
            }
        });
        if (this.options.closeOnEscape) {
            $(this.element).keydown(function (e) {
                if (e.which == 27) {
                    self.hide();
                }
            });
        }
    },
    show: function () {
        var self = this;

        this.hide();
        this.element.css({ left: 0, top: 0 });

        this.updatePos();

        this.element.show();
        $('input:first', this.element).select().focus();
    },
    hide: function () {
        this.element.hide();
    },
    updatePos: function () {
        if (!this.target) {
            return;
        }
        this.element.hide().css({ left: 0, top: 0 });

        var top = $(this.target).bottom() + 5;
        var left = $(this.target).left() + $(this.target).outerWidth() / 2 - this.element.outerWidth() / 2;
        if (left < this.options.offset) {
            left = this.options.offset;
        }
        if (left + this.element.outerWidth() > $(window).width() - this.options.offset) {
            left = $(window).width() - this.element.outerWidth() - this.options.offset;
        }

        this.element.css({
            left: left,
            top: top
        });
        $('tbody', this.element).width(this.element.width());

        this.element.show();
        this.arrow.css('left', $(this.target).left() + $(this.target).outerWidth() / 2 - left - 7);
    }
};

/* Folder browse dialog */
$.fn.browseFolder = function () {
    var self = this;
    this.css({
        'padding-left': 20,
        'margin-left': -19
    });
    $('<a href="javascript:;"><img src="images/browse.png" width="16" height="16" /></a>').prependTo(this.parent()).css({
        position: 'relative',
        left: 4,
        top: 0
    }).click(function () {
        $(this).guard(function () {
            Local.ajax('browse-dialog', $(self).val(), function (data) {
                if (data) {
                    self.val(data.selectedPath);
                    self.trigger('change');
                }
            }, self);
        });
    });
};
ko.bindingHandlers.browseFolder = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        $(element).browseFolder();
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
    }
};

    var Services = {
        localSupport: typeof Awesomium !== 'undefined',
        local: function (obj) {
            if (!this.localSupport) {
                alert('Local call is not supported!!!');
                return;
            }

            var defaultOptions = {
                method: null,
                params: null,
                complete: null,
                update: null,
                error: null,
                target: null
            };
            var options = defaultOptions;
            if (!TypeUtil.isString(obj)) {
                options = $.extend({}, defaultOptions, obj);
            }
            else {
                options.method = arguments[0];
                options.params = arguments[1];
                options.complete = arguments[2];
                if (typeof arguments[3] === 'function') {
                    options.update = arguments[3];
                    options.target = arguments[4];
                }
                else {
                    options.target = arguments[3];
                }
            }

            var id = Async.regist(options.target, options.complete, options.update, options.error);
            Awesomium.InvokeMethod(options.method, JSON.stringify(options.params), id);
        },
        remote: function (method, params, options) {
            options.data = {
                method: method,
                parameters: JSON.stringify(params)
            };
            options.dataType = 'json';
            $.ajax(options);
        }
    };

/* Asynchronous manager */
    function AsyncManager() {
        this.queue = [];
        this.id = 0;
    }
    AsyncManager.prototype = {
        popTask: function (id) {
            for (var i = 0; i < this.queue.length; i++) {
                if (this.queue[i].id == id) {
                    var task = this.queue[i];
                    this.queue.splice(i, 1);
                    return task;
                }
            }
            return null;
        },
        getTask: function (id) {
            for (var i = 0; i < this.queue.length; i++) {
                if (this.queue[i].id == id) {
                    return this.queue[i];
                }
            }
            return null;
        },
        finishTask: function (id, data) {
            var task = this.popTask(id);
            if (task) {
                var obj = JSON.parse(data);
                if (typeof obj.status !== 'undefined') {
                    if (task.error) {
                        task.error.call(task.obj, obj);
                    }
                }
                else if (task.complete) {
                    task.complete.call(task.obj, obj);
                }
            }
        },
        updateTask: function (id, data) {
            var task = this.getTask(id);
            if (task && task.update) {
                var obj = JSON.parse(data);
                task.update.call(task.obj, obj);
            }
        },
        regist: function (obj, complete, update, error) {
            if (!complete && !update && !error) {
                return -1;
            }

            var id = this.id++;
            this.queue.push({
                id: id,
                obj: obj,
                complete: complete,
                update: update,
                error: error
            });
            return id;
        }
    };
    var Async = new AsyncManager();